package com.example.smartpluginablehotfix;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;

import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexClassLoader;

public class HotfixApplication extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        File apk = new File(getCacheDir() + "/hotfix.dex");
        if (apk.exists()) {
            try {
                //获取当前的classLoader
                ClassLoader originalLoader = getClassLoader();
                //创建baseClassLoader
                DexClassLoader classLoader = new DexClassLoader(apk.getPath(), getCacheDir().getPath(), null, null);
                //获取baseClassLoader中的pathList字段
                Class loaderClass = BaseDexClassLoader.class;
                Field pathListField = loaderClass.getDeclaredField("pathList");
                //设置pathLIstFIled可以访问
                pathListField.setAccessible(true);
                //获取classLoader里面的pathList对象（获取apk里面的额pathList）
                Object pathListObject = pathListField.get(classLoader);
                //获取dexpathList类名
                Class pathlistClass = pathListObject.getClass();
                //获取字段dexElements
                Field dexElementsFiled = pathlistClass.getDeclaredField("dexElements");
                dexElementsFiled.setAccessible(true);
                //获取新的dexElements对象
                Object dexElementsObject = dexElementsFiled.get(pathListObject);

                //获取originalLoader(也就是当前apk)里面的pathList对象
                Object originalPathListObject = pathListField.get(originalLoader);
                //获取旧的dexElements对象
                Object orginalDexElementsObject = dexElementsFiled.get(originalPathListObject);
                //因为新的elements里面的dex和旧的elements里面的dex里面有相同的dex,所以要把新的dex放在前面，读取的时候读到前面的dex,就不会在读后面旧的dex了
                //把新的放在0号，其它的遍历放在后面。也就是新增0,0变1,1变2
                int oldLength = Array.getLength(orginalDexElementsObject);
                int newLength = Array.getLength(dexElementsObject);
                Object concatDexElementsObject = Array.newInstance(dexElementsObject.getClass().getComponentType(), oldLength + newLength);
                for (int i = 0; i < newLength; i++) {
                    Array.set(concatDexElementsObject, i, Array.get(dexElementsObject, i));
                }
                for (int i = 0; i < oldLength; i++) {
                    Array.set(concatDexElementsObject, newLength + i, Array.get(orginalDexElementsObject, i));
                }
                dexElementsFiled.set(originalPathListObject, concatDexElementsObject);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            Log.e("======", "======path:" + apk.getAbsolutePath().toString());
        }
    }
}
